#!/usr/bin/env python
# encoding: utf-8
"""
Shovelhead
File: Shovelhead.py
Author: Myriam Boucher

Sound synthesis of a Shovelhead engine.

The Shovelhead is an air-cooled, 45 degree, V-twin motorcycle engine manufactured
from 1966 to 1984 by Harley-Davidson. Initial models had an engine displacement
of 1,208 cc (74 cu in). After 1978, this was increased to 1,340 cc (82 cu in) for
Harley's Big Twin bikes. Source: <http://en.wikipedia.org/wiki/Harley-Davidson_Shovelhead_engine>.
"""

from pyo import *
import random
import math
from LoopAdsr import *
from Gear import *
from Engine import *
import time

class Shovelhead(Engine):
    
    def __init__(self):
        Engine.__init__(self)
        
        # effects on its rattling engine, noise
        self.noiseResonnance = PinkNoise(mul=self.env3.sig(), add=0)
        self.r5 = Randi(min=0.22, max=.32, freq=1.00, mul=1, add=0)
        self.r6 = Randi(min=0.10, max=.15, freq=1.00, mul=1, add=0)
        self.resonnanceEngine = IRPulse(self.noiseResonnance, freq=self.r5*1000, bw=self.r6*10000, type=3,
                                        order=250, mul = [.2,self.env2.sig()/2])
        self.noiseEngine = Rossler(pitch=random.choice([.02, .40, .65, .55, .35, .25]), chaos=random.choice([0.50, .8, .45, .65]),
                                   stereo=True, mul=self.env2.sig()/2, add=0)
        self.noiseResonnance2 = Noise(.5)
        self.r9 = Randi(min=0.25, max=.33, freq=[2.5,3.4,2.2, 1.2], mul=1, add=0)
        self.resonnanceEngine2 = IRPulse(self.noiseResonnance2, freq=self.r9*1000, bw=2000, type=3, order=152,
                                         mul = [.2, self.env.sig(), .5, self.env2.sig()])
        self.rossShovel = Rossler(pitch=.3, chaos=0.82, stereo=False, mul=self.env.sig(), add=0) 
        # mix - snap engine
        self.pan2DShovelhead = SPan(self.eqPinkNoise  + self.clipFm +   self.filterSinwave + self.noiseEngine +
                                self.resonnanceEngine + self.resonnanceEngine2 + self.rossShovel, outs=2, pan=0.50, mul=.5, add=0)
        self.setPan2D(self.pan2DShovelhead)
        self.mixShovelhead = Mix(self.pan2DShovelhead, voices=2)
        self.setMix(self.mixShovelhead)
        
        # kickStart: crankshaft sound
        self.env4 = LoopAdsr(list=[(0,0),(250,1),(1000,0.0005),(1200,0.0005),(1350,0)],
                dur=0.09, min=0.01, max=0.03, freq=[10,10.2])
        self.pinkNoiseKS = PinkNoise(mul=self.env4.sig(), add=0)
        self.revKickStart = WGVerb(self.pinkNoiseKS, feedback=0.50, cutoff=5000, bal=0.32, mul=.38, add=0)
        self.mixNoStartingShovelhead = Mix(self.revKickStart)
        self.setMixNoStarting(self.mixNoStartingShovelhead)
        
    def changeSpeed(self, x):  
        # changes the sound of the engine when changing speed.        
        self.fm.carrier += x*8
        self.fm.ratio += x/10
        self.fm.ind1 *= x*10
        self.fm.ind2 += x*2
        self.sinwave.freq += x*8
        self.fm2.carrier += x*9
        self.fm2.ratio += x/16
        self.fm2.ind1 *= x*15
        self.fm2.ind2 += x*3
        self.resonnanceEngine.freq += x*120
        self.resonnanceEngine2.freq += x*100
     
    def playShovelhead(self):
        # plays the audio objects.
        self.noiseEngine.play()
        self.noiseResonnance.play()
        self.resonnanceEngine.play()
        self.resonnanceEngine2.play()
        self.noiseResonnance2.play()
        self.pan2DShovelhead.play()
        self.r5.play()
        self.r6.play()
        self.r9.play()
        self.pinkNoiseKS.play()
        self.revKickStart.play()
        self.rossShovel.play()
        
    
    def stopShovelhead(self):
        # stop the audio objects.
        self.noiseEngine.stop()
        self.noiseResonnance.stop()
        self.resonnanceEngine.stop()
        self.resonnanceEngine2.stop()
        self.noiseResonnance2.stop()
        self.pan2DShovelhead.stop()
        self.r5.stop()
        self.r6.stop()
        self.r9.stop()
        self.pinkNoiseKS.stop()
        self.revKickStart.stop()
        self.rossShovel.stop()
